﻿using System;
using System.Diagnostics;
using System.Windows.Input;

namespace SSTU.ViewModel.Core
{
	/// <summary>
	/// Parametrized command with delegates.
	/// </summary>
	public class DelegateCommand<T> : ICommand
		where T : class
	{
		#region Fields

		readonly Action<T> _execute;
		readonly Predicate<T> _canExecute;

		#endregion // Fields

		#region Constructors

		/// <summary>
		/// Initializes a new instance of the <see cref="DelegateCommand&lt;T&gt;"/> class.
		/// </summary>
		public DelegateCommand(Action<T> execute)
			: this(execute, null)
		{
		}

		/// <summary>
		/// Initializes a new instance of the <see cref="DelegateCommand&lt;T&gt;"/> class.
		/// </summary>
		public DelegateCommand(Action<T> execute, Predicate<T> canExecute)
		{
			if (execute == null)
			{
				throw new ArgumentNullException("execute");
			}
			_execute = execute;
			_canExecute = canExecute;
		}

		#endregion // Constructors

		#region ICommand Members

		/// <summary>
		/// Defines the method that determines whether the command can execute in its current state.
		/// </summary>
		/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
		[DebuggerStepThrough]
		public bool CanExecute(object parameter)
		{
			return _canExecute == null ? true : _canExecute(parameter as T);
		}

		/// <summary>
		/// Occurs when changes occur that affect whether the command should execute.
		/// </summary>
		public event EventHandler CanExecuteChanged;

		/// <summary>
		/// Defines the method to be called when the command is invoked.
		/// </summary>
		/// <param name="parameter">Data used by the command. If the command does not require data to be passed, this object can be set to null.</param>
		public void Execute(object parameter)
		{
			_execute(parameter as T);
		}

		#endregion // ICommand Members

		/// <summary>
		/// Raises that can execute changed.
		/// </summary>
		public void RaiseCanExecuteChanged()
		{
			if (CanExecuteChanged != null)
			{
				CanExecuteChanged(this, new EventArgs());
			}
		}
	}
}
